package com.zzk.www.nettyServer.handler;

import com.zzk.www.domain.User;
import com.zzk.www.nettyServer.tool.RequestApi;
import com.zzk.www.service.MessageHelperService;
import com.zzk.www.tool.cache.CacheService;
import com.zzk.www.tool.common.BeanHolder;
import com.zzk.www.tool.constants.CacheConstant;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.stream.ChunkedNioFile;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.RandomAccessFile;
import java.net.URL;
import java.util.Random;

/**
 * Created by zzk on 2017/12/17.
 */


/*
*
* HttpRequestHandler 做了下面几件事，
*
* 1.如果该 HTTP 请求被发送到URI “/ws”，调用 FullHttpRequest 上的 retain()，并通过调用 fireChannelRead(msg) 转发到下一个 ChannelInboundHandler。
* retain() 是必要的，因为 channelRead() 完成后，它会调用 FullHttpRequest 上的 release() 来释放其资源。
* （请参考我们先前的 SimpleChannelInboundHandler 在第6章中讨论）
* 2.如果客户端发送的 HTTP 1.1 头是“Expect: 100-continue” ，将发送“100 Continue”的响应。
* 3.在 头被设置后，写一个 HttpResponse 返回给客户端。注意，这是不是 FullHttpResponse，唯一的反应的第一部分。
* 此外，我们不使用 writeAndFlush() 在这里 - 这个是在最后完成。
* 4.如果没有加密也不压缩，要达到最大的效率可以是通过存储 index.html 的内容在一个 DefaultFileRegion 实现。这将利用零拷贝来执行传输。
* 出于这个原因，我们检查，看看是否有一个 SslHandler 在 ChannelPipeline 中。另外，我们使用 ChunkedNioFile。
* 5.写 LastHttpContent 来标记响应的结束，并终止它
* 6.如果不要求 keepalive ，添加 ChannelFutureListener 到 ChannelFuture 对象的最后写入，并关闭连接。注意，这里我们调用 writeAndFlush() 来刷新所有以前写的信息。
* */

public class ZZKHttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    private static Logger logger = Logger.getLogger(ZZKHttpRequestHandler.class);

    private static File index;


    static {

        URL location = ZZKHttpRequestHandler.class.getProtectionDomain().getCodeSource().getLocation();

        try {
            String path = location.toURI() + "page/index.html";

            path = !path.contains("file:") ? path : path.substring(5);

            index = new File(path);

            System.out.println(path);
        } catch (Exception e) {

            e.printStackTrace();
        }


    }



    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {


        if (request.getUri().contains(RequestApi.chatUri)) {

            ctx.fireChannelRead(request.retain());

        } else if (request.getUri().equals(RequestApi.destoryUri)) {

            BeanHolder.get(MessageHelperService.class).destory();

        } else if(request.getUri().equals(RequestApi.generateTestData)){

            generateTestData(ctx,request);

        } else {
            if (HttpHeaders.is100ContinueExpected(request)) {
                FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
                ctx.writeAndFlush(response);
                //3
            }

            RandomAccessFile file = new RandomAccessFile(index, "r");//4

            HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK);
            response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/html; charset=UTF-8");

            boolean keepAlive = HttpHeaders.isKeepAlive(request);

            if (keepAlive) {                                        //5
                response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, file.length());
                response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
            }
            ctx.write(response);                    //6

//            if (ctx.pipeline().get(SslHandler.class) == null) {     //7
//                ctx.write(new DefaultFileRegion(file.getChannel(), 0, file.length()));
//            } else {
//                ctx.write(new ChunkedNioFile(file.getChannel()));
//            }


            ctx.write(new ChunkedNioFile(file.getChannel()));

            ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);           //8
            if (!keepAlive) {
                future.addListener(ChannelFutureListener.CLOSE);        //9
            }

            file.close();
        }



        /*
        扩展 SimpleChannelInboundHandler 用于处理 FullHttpRequest信息

        如果请求是 WebSocket 升级，递增引用计数器（保留）并且将它传递给在 ChannelPipeline 中的下个 ChannelInboundHandler

        处理符合 HTTP 1.1的 “100 Continue” 请求

        读取默认的 WebsocketChatClient.html 页面

        判断 keepalive 是否在请求头里面

        写 HttpResponse 到客户端

        写 index.html 到客户端，判断 SslHandler 是否在 ChannelPipeline 来决定是使用 DefaultFileRegion 还是 ChunkedNioFile

        写并刷新 LastHttpContent 到客户端，标记响应完成

        如果 keepalive 没有要求，当写完成时，关闭 Channel*
         */

    }


    //生成测试数据
    private void generateTestData(ChannelHandlerContext ctx, FullHttpRequest request) {


        String name = "笪幼柏,衡沛岚,析天翰,滕银河,图门智敏,谌语薇,连幻珊,局家骏,鄞燕子,顾天心,墨绿旋,车鸿骞,纪乐山,功丹彤,咸珠雨,愚盼夏,淦夏蓉,令狐尔晴雪凝,介子楠,己水丹,鹿彤霞,溥小星,谷映天,圣香馨,老清霁,独雅柔,士夜南,叶修平,肖梦安,硕昆纬,季凯风,巢秀梅,涂骊媛,蒯怀玉,生昌茂,屈芝宇,爱霞姝,西门秋柏,苗华芝,刚丝琦,蒉和璧,雪青旋,悟思琪,况寄蓉,淳于盼易,绍梓露,宰浩大,侍若云,容琼英,龙嘉澍,敏琼音,祈瀚漠,苦天蓉,常慧丽,强雪枫,道碧玉,山俊雅,家庄雅,金乐圣,由飞莲,皇甫淑华,学斯琪,良新雪,竹启颜,薛刚捷,乌雅和安,令夏旋,卞新筠,蓬星火,万昕雨,广悦乐,申屠旭鹏,万俟景铄,宿湛芳,闾荷珠,徭绮云,辟长钰,邓以松,鲍玟丽,姚兴文,古醉蝶,孔唱月,夏觅翠,厉诗珊,绪嘉懿,胡秀媚,欧梦寒,百乐康,覃清淑,沃巍奕,说芳馥,达灵阳,左丘韵诗,郏峻熙,皇嘉言,汉冷玉,汪晴霞,邴德业,东门春芳,御海昌,谯霞文,宋慧美,子车密如,鞠涵易,俞巧凡,矫易巧,柏涵蕾,抗慕卉,秘怜阳,别颐然,毛夜卉,亓官鹏涛,毕飞烟,仵安双,蔚诗霜,白安白,茂星波,海芬菲,舜海之,藤辰皓,阚雪瑶,公羊洁玉,尤迎夏,羊舌仪芳,牵丽佳,系海阳,眭鹤梦,易尔风,红香岚,花耘豪,蛮寄灵,买蓝尹,前代珊,拓跋依云,庾曼雁,乾欣畅,欧阳霞雰,通珊珊,伍平露,蒋采南,受丹丹,郗从阳,尉迟雁卉,豆映寒,尹香天,巫痴香,丛浩气,段干醉巧,桐向露,武映冬,公叔瀚昂,解新儿,召诗蕊,世鸿煊,檀北嘉,夹谷嘉颖,让阳朔,赛秋白,边从珊,郦彦慧,舒清佳,萧文心,兰梦华,牛乐安,绳高原,岑和顺,理云亭,僪嘉悦,乐正睿德,委依琴,天凌晓,占安安,颛孙晶燕,雀永思,关向彤,本珍瑞,濮阳鸿文,旷淳美,兆忆秋,问安春,郯歌飞,守斯伯,种宛白,励曼妮,闻人慧秀,闫向真,斋小凝,尉俊雅,农代秋,申高扬,叔震博,北乃心,颜初南,房子萱,乙千儿,赫思雨,贯飞雨,昔丹蝶,姜颖然,於妮子,后寒松,秋锦欣,瑞秋芸,史安平,渠访冬,脱飞兰,于语梦,战夜春,慈宜春,严秀筠,冠和悌,偶向雁,黄雨彤,风曼容,出晶茹,宗天真,夙芷荷,公冶寒烟,保德容,畅宏扬,森雅洁,姬洛灵,能晴照,弓俊杰,闾丘瀚彭,碧又青,符云霞,曾鸿轩,校采文,卫光霁,多思敏,斯骊洁,贲静枫,公绮琴,逢子石,轩辕水风,鲜元纬,壬天亦,运梦凡,沙春柏,支暄妍,仲安宁,裔天菱,文如曼,弭皓月,义乐咏,勇沛文,性欣嘉,宫白亦,吴沛雯,衣曼丽,铁怀慕,紫新梅,尧凌丝,禹幻丝,祝文虹,依曼寒,洋丝娜,孙念之,迟妍歌,冀如曼,甫香洁,熊秋翠,诗心诺,堂娜兰,敛菊月,洪胤运,练琛丽,霍俊豪,真昆峰,逮高歌,褚骊雪,邰弘益,掌锐志,僧司辰,皮雪卉,闵曼冬,庹香菱,彭绮思,温乐双,梁金枝,慕容志学,莱梦泽,剑俊晤,鱼雅韵,";
        String[] names = name.split(",");
        Random random = new Random();

        for(int i = 0 ;i<10 ;i++){
            String fullName = names[random.nextInt(names.length)];
            User user = new User(""+i, fullName,""+i+"号");
            BeanHolder.get(CacheService.class,"redisCacheService").set(CacheConstant.Auth.loginUser+"_"+user.getUserId(),user);
            BeanHolder.get(CacheService.class,"redisCacheService").set(CacheConstant.Auth.token+"_"+i,user);


            logger.info("loginUser ====="+CacheConstant.Auth.loginUser+user.getUserId()+"im_token=============="+CacheConstant.Auth.token+i);

        }

        returnOkCode(ctx,request);
    }

    private void returnOkCode(ChannelHandlerContext ctx,FullHttpRequest request){

        HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK);
        response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/html; charset=UTF-8");

        boolean keepAlive = HttpHeaders.isKeepAlive(request);

        if (keepAlive) {                                        //5
            response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
        }
        ctx.writeAndFlush(response);

    }


}
